import json
import os
import asyncio
import time
import sys
import subprocess
import multiprocessing
from datetime import datetime
from fastapi import  APIRouter,Response,Request,Query,BackgroundTasks
from fastapi.responses import JSONResponse,StreamingResponse
from pydantic import BaseModel
import xml.etree.ElementTree as ET
import re
from redis.asyncio import Redis  # 从redis.asyncio导入异步客户端

ssetopology_router = APIRouter()
def shell_cmd(command):
        # 构造管道命令（注意：awk的单引号需转义，或用双引号包裹整个命令）
    try:
        # 执行命令：shell=True让shell处理管道，text=True让输出为字符串
        result = subprocess.run(
            command,
            shell=True,
            stdout=subprocess.PIPE,  # 捕获标准输出（状态）
            stderr=subprocess.PIPE,  # 捕获标准错误（错误信息）
            text=True,               # 输出为字符串（而非字节）
            timeout=10               # 超时时间（避免命令挂起）
        )
        if result.returncode == 0:
            status = result.stdout.strip()
            return status
        else:
            # 命令执行失败（如qm出错）
            error_msg = result.stderr.strip()
            return f"命令执行失败：{error_msg}"
    except subprocess.TimeoutExpired:
        return "错误：命令执行超时"
    except Exception as e:
        return f"未知错误：{str(e)}"

@ssetopology_router.post("/queryallnodes")
async def query_all_nodes(request: Request,data:dict,topologyId:str=Query(...)):
    nodelist = data['nodelist']
    k = []
    for vmname in nodelist:
        cmd = f'ps aux | grep {topologyId}-{vmname}'
        result = subprocess.run(
        cmd,
        shell=True,
        stdout=subprocess.PIPE,  # 捕获标准输出（状态）
        stderr=subprocess.PIPE,  # 捕获标准错误（错误信息）
        text=True,               # 输出为字符串（而非字节）
        timeout=10               # 超时时间（避免命令挂起）
        )
        if '/usr/bin/kvm ' in result.stdout:
            status = 'running'
        else:
            status = 'stoped'
        re = {'name':vmname,'status':status}
        k.append(re)
    return JSONResponse(content={"code": 200, "message": "success", "data": k})
def mul_start_all_nodes(node,topologyId):
    asyncio.run(task_startallnodes(node,topologyId))
async def task_startallnodes(node,topologyId):#执行开机的命令
    # #写文件的方式模拟启动
    async with Redis.from_url(url="redis://localhost:6379/0",decode_responses=True) as redis:
        #获取node名字对应的vmid
        topp_set = await redis.smembers(f'{topologyId}_map')
        topo_list = [json.loads(item) for item in list(topp_set)]
        vmid = [item['vmid'] for item in topo_list if item['name'] == node][0]
        cmd = f'qm start {vmid}'
        shell_cmd(cmd)
#批量操作、开机、关机、删除
@ssetopology_router.post("/startallnodes")
async def start_all_nodes( request: Request,data:dict,topologyId:str=Query(...)):
    if data['nodelist'] == []:
        return JSONResponse(content={"code": 200, "message": "success", "data": data})
    else:
        for i in data['nodelist']:
            multiprocessing.Process(target=mul_start_all_nodes, args=(i,topologyId)).start()
        return JSONResponse(content={"code": 200, "message": "success", "data": data})


def mul_stop_all_nodes(data,topologyId):
    asyncio.run(task_stopallnodes(data,topologyId))
async def task_stopallnodes(data,topologyId):
    nodelist = data['nodelist']
    for i in nodelist:
        cmd = f'ps aux | grep {topologyId}-{i}'#先查询释放运行中
        result = subprocess.run(
            cmd,
            shell=True,
            stdout=subprocess.PIPE,  # 捕获标准输出（命令输出）
            stderr=subprocess.PIPE,  # 捕获标准错误（错误信息）
            text=True,               # 输出为字符串（而非字节）
            timeout=10               # 超时时间（避免命令挂起）
        )
        r = result.stdout.split('\n')
        for j in r:
            if '/usr/bin/kvm' in j:
                pid = j.split()[1]
                cmd = f'kill {pid}'
                shell_cmd(cmd)
                break
@ssetopology_router.post("/stopallnodes")
async def stop_all_nodes( request: Request,data:dict,topologyId:str=Query(...)):
    if data == []:
        return JSONResponse(content={"code": 200, "message": "success", "data": data})
    else:
        #background_tasks.add_task(task_stopallnodes,data,topologyId)
        multiprocessing.Process(target=mul_stop_all_nodes, args=(data,topologyId)).start()
        return JSONResponse(content={"code": 200, "message": "success", "data": data})

def mul_delete_all_nodes(data,topologyId):
    asyncio.run(delete_all_nodes_task(data,topologyId))

async def delete_all_nodes_task(data,topologyId):
    async with Redis.from_url(url="redis://localhost:6379/0",decode_responses=True) as redis:
        topp_set = await redis.smembers(f'{topologyId}_map')
        topo_list = [json.loads(item) for item in list(topp_set)]
        currentNodeList = data['currentNodeList']
        selectInterfaceId = data['selectInterfaceId']
        selectedEdgesSnodeTnode = data['selectedEdgesSnodeTnode']
        otherNodeList = data['otherNodeList']
        for i in currentNodeList:
            if i['type'] == 'UserTask':
                vmname = i['id']
                vmid = [item['vmid'] for item in topo_list if item['name'] == vmname][0]
                cmd = f'rm -rf /etc/pve/qemu-server/{vmid}.conf'
                shell_cmd(cmd)
                cmd = f'rm -rf /data/sda/images/{vmid}'
                shell_cmd(cmd)
                #释放节点id
                k = {'name':vmname,'vmid':vmid}
                await redis.srem(f'{topologyId}_map', json.dumps(k))  # 从Set中删除该元素
                #给vmid加回被使用的标记
                await redis.zadd(f'{topologyId}_vmid', {vmid:vmid})
        
        for i in selectInterfaceId:#删除网桥
            if i != 0:
                # # 关闭网桥（设置为DOWN状态）
                del_bridge_step1 = f'ip link set vmbr{i} down'
                shell_cmd(del_bridge_step1)
                # # 删除网桥（vmbr10）
                del_bridge_step2 = f'brctl delbr vmbr{i}'
                shell_cmd(del_bridge_step2)
                #删除配置sed -i '/^auto vmbr1$/,/bridge-fd 0$/d' interfaces
                del_bridge_step3 = f"sed -i '/^auto vmbr{i}$/,/bridge-fd 0$/d' /etc/network/interfaces"
                shell_cmd(del_bridge_step3)
                #在可用的bridgeid表里面添加对应的id
                await redis.zadd(f'{topologyId}_bridgeid',{str(i):i})
                #删除映射关系
                for j in selectedEdgesSnodeTnode:
                    currSnodeId = j['sourceNodeId']
                    currTnodeId = j['targetNodeId']
                    tag=''.join(sorted([currSnodeId, currTnodeId]))
                    map = {'name':tag,'bridgeid':f'vmbr{i}'}
                    await redis.srem(f'{topologyId}_bridgeid_map',json.dumps(map))
        #以上是删除选中节点的操作，还需要操作未选择的节点
        for m in otherNodeList:
            try:
                otherNodeStatus = m['otherNodeStatus']
            except KeyError:
                otherNodeStatus = 'down'
            try:
                otherNodeType = m['otherNodeType']
            except KeyError:
                otherNodeType = m['otherNodetype']
            if otherNodeType == 'UserTask':
                vmname = m['id']
                cid = m['cid']
                tag=''.join(sorted([vmname, cid]))
                tnodevmid = [item['vmid'] for item in topo_list if item['name'] == vmname][0]
                for index,n in enumerate(m['interfaceid']):
                    k = m['otherNodeEth'][index]
                    xlname = k['id']
                    teth = k[xlname]
                    tnode_Ethernet = m['otherNodeEthernet']
                    tnode_net = tnode_Ethernet.index(teth)
                    if otherNodeStatus =='down':
                        unmount_tnode_cmd = f"sed -i '/^net{tnode_net}:/s/bridge=vmbr[0-9]\+/bridge=tmpbr0,link_down=1/' /etc/pve/qemu-server/{tnodevmid}.conf"
                        shell_cmd(unmount_tnode_cmd)
                    else:
                        result = subprocess.run(f"cat /etc/pve/qemu-server/{tnodevmid}.conf | grep 'net{tnode_net}:' ",stdout=subprocess.PIPE,shell=True,text=True)
                        netres = result.stdout.strip()
                        pattern = r'(\w+)=([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})'
                        match = re.search(pattern, netres)
                        if match:
                            interface_type = match.group(1)  # 第1组：接口类型
                            mac_address = match.group(2)     # 第2组：MAC地址
                        #获取接口类型、mac地址
                        cmd = f"qm set {tnodevmid} --net{tnode_net} {interface_type}={mac_address},bridge=tmpbr0,link_down=1"
                        shell_cmd(cmd)
                    #修改接口关联的bridge
                    if n != 0:
                        map = {'name':tag,'bridgeid':f'vmbr{n}'}
                        # # 关闭网桥（设置为DOWN状态）
                        del_bridge_step1 = f'ip link set vmbr{n} down'
                        shell_cmd(del_bridge_step1)
                        # # 删除网桥（vmbr10）
                        del_bridge_step2 = f'brctl delbr vmbr{n}'
                        shell_cmd(del_bridge_step2)
                        #删除配置sed -i '/^auto vmbr1$/,/bridge-fd 0$/d' interfaces
                        del_bridge_step3 = f"sed -i '/^auto vmbr{n}$/,/bridge-fd 0$/d' /etc/network/interfaces"
                        shell_cmd(del_bridge_step3)
                        #在可用的bridgeid表里面添加对应的id
                        await redis.zadd(f'{topologyId}_bridgeid',{str(n):n})
                        #删除映射关系
                        await redis.srem(f'{topologyId}_bridgeid_map',json.dumps(map))
        
@ssetopology_router.post("/deleteallnodes")
async def delete_all_nodes(request: Request,data:dict,topologyId:str=Query(...)):
    multiprocessing.Process(target=mul_delete_all_nodes, args=(data,topologyId)).start()
    return 'ok'